package com.just.gatewayapi.core;

import org.springframework.context.ApplicationContext;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * 收集API注解
 */
public class ApiStore {
    private ApplicationContext applicationContext;
    private Map<String, ApiRunnable> apiMap = new HashMap<>();

    public ApiStore(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;

    }

    //对标记的API方法进行绑定
    //getDeclaredMethods(),该方法是获取本类中的所有方法，包括私有的(private、protected、默认以及public)的方法。
    public void loadApiFromSpringBeans() {
        String[] names = applicationContext.getBeanDefinitionNames();
        Class<?> type;
        for (String name : names) {
            type = applicationContext.getType(name);
            for (Method method : type.getDeclaredMethods()) {
                APIMapping apiMapping = method.getDeclaredAnnotation(APIMapping.class);
                if (apiMapping != null) {
                    addApiItem(apiMapping, name, method);
                }
            }
        }
    }

    private void addApiItem(APIMapping apiMapping, String beanName, Method method) {
        ApiRunnable apiRunnable = new ApiRunnable();
        apiRunnable.setApiName(apiMapping.value());
        apiRunnable.setMethod(apiMapping.method().getValue());
        apiRunnable.setTargetName(beanName);
        apiRunnable.setTargetMethod(method);
        apiMap.put(apiMapping.value(), apiRunnable);
    }

    public ApiRunnable findApiRunnable(String apiName) {
        return apiMap.get(apiName);
    }


    private class ApiRunnable {
        private String apiName;
        private Method targetMethod;
        private String targetName;
        private Object target;
        private String method;

        public Object run(Object... args) throws InvocationTargetException, IllegalAccessException {
            if (target == null) {
                target = applicationContext.getBean(targetName);
            }
            return targetMethod.invoke(target, args);
        }

        public Object getTarget() {
            if (target == null) {
                target = applicationContext.getBean(targetName);
            }
            return target;
        }

        public String getApiName() {
            return apiName;
        }

        public void setApiName(String apiName) {
            this.apiName = apiName;
        }

        public Method getTargetMethod() {
            return targetMethod;
        }

        public void setTargetMethod(Method targetMethod) {
            this.targetMethod = targetMethod;
        }

        public String getTargetName() {
            return targetName;
        }

        public void setTargetName(String targetName) {
            this.targetName = targetName;
        }

        public void setTarget(Object target) {
            this.target = target;
        }

        public String getMethod() {
            return method;
        }

        public void setMethod(String method) {
            this.method = method;
        }
    }
}
